package gui;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;

import javax.swing.ButtonGroup;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.ListSelectionModel;
import javax.swing.ScrollPaneConstants;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.border.EtchedBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import dataStructure.Path;
import fn.Function;

public class MainFrame extends JFrame {

	private static final long serialVersionUID = 2666107860996237938L;

	public JPanel contentPane;
	public JMenuBar menuBar;
	public JMenu mnFile;
	public JMenu mnView;
	public JMenu mnHelp;
	public JMenuItem mntmNew;
	public JMenuItem mntmOpen;
	public JMenuItem mntmSave;
	public JSeparator separator;
	public JMenuItem mntmExport;
	public JSeparator separator_1;
	public JMenuItem mntmExit;
	public JCheckBoxMenuItem chckbxmntmGrid;
	public JMenuItem mntmHelp;
	public JSeparator separator_4;
	public JMenuItem mntmAbout;
	public JToolBar toolBar;
	public JToggleButton tglbtnCreate;
	public JToggleButton tglbtnModify;
	public JToggleButton tglbtnEvaluate;
	public JScrollPane scrlEval;
	public JScrollPane scrlCanvas;
	public JTextField lblStatus;
	public JPanel pnlEval;
	public MainFrame thisFrame;
	public MyCanvas pnlCanvas;

	public ArrayList<Tool> tools;
	public PanelFunction panelFunction;
	public JButton btnEval;
	public JButton btnInput;
	public JButton btnOutput;
	public JLabel lblPaths;
	public JSeparator separator_2;
	public JScrollPane scrollPane;
	public JLabel lblDetermenants;
	public JSeparator separator_3;
	public JScrollPane scrollPane_1;
	public JList<ArrayList<Path<UI_Node>>> lstPath;
	public JList<Function> lstDtrm;

	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
					MainFrame frame = null;
					try {
						frame = new MainFrame();
						frame.setVisible(true);
					} catch (Exception e) {
						frame.error("Fatal error. Please restart the application.");
					}
				} catch (Exception e) {
					JOptionPane.showMessageDialog(null, "Couldn't load system specific Look And Feel.");
				}
			}
		});
	}

	public MainFrame() {
		init();
	}

	private void init() {
		setPreferredSize(new Dimension(700, 500));
		setFocusTraversalKeysEnabled(false);
		setFocusCycleRoot(false);
		setFocusable(false);
		thisFrame = this;
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 700, 500);

		// MENU BAR

		menuBar = new JMenuBar();
		menuBar.setFocusable(false);
		setJMenuBar(menuBar);

		mnFile = new JMenu("File");
		mnFile.setFocusTraversalKeysEnabled(false);
		mnFile.setFocusable(false);
		menuBar.add(mnFile);

		mntmNew = new JMenuItem("New");
		mntmNew.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				do_mntmNew_actionPerformed(e);
			}
		});
		mnFile.add(mntmNew);

		mntmOpen = new JMenuItem("Open...");
		mntmOpen.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				do_mntmOpen_actionPerformed(e);
			}
		});
		mnFile.add(mntmOpen);

		mntmSave = new JMenuItem("Save...");
		mntmSave.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				do_mntmSave_actionPerformed(e);
			}
		});
		mnFile.add(mntmSave);

		separator = new JSeparator();
		mnFile.add(separator);

		mntmExport = new JMenuItem("Export...");
		mnFile.add(mntmExport);

		separator_1 = new JSeparator();
		mnFile.add(separator_1);

		mntmExit = new JMenuItem("Exit");
		mnFile.add(mntmExit);

		mnView = new JMenu("View");
		mnView.setFocusTraversalKeysEnabled(false);
		mnView.setFocusable(false);
		menuBar.add(mnView);

		chckbxmntmGrid = new JCheckBoxMenuItem("Grid");
		chckbxmntmGrid.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				do_chckbxmntmGrid_actionPerformed(e);
			}
		});
		mnView.add(chckbxmntmGrid);

		mnHelp = new JMenu("Help");
		mnHelp.setFocusTraversalKeysEnabled(false);
		mnHelp.setFocusable(false);
		menuBar.add(mnHelp);

		mntmHelp = new JMenuItem("Help...");
		mnHelp.add(mntmHelp);

		separator_4 = new JSeparator();
		mnHelp.add(separator_4);

		mntmAbout = new JMenuItem("About");
		mnHelp.add(mntmAbout);
		contentPane = new JPanel();
		contentPane.setFocusTraversalKeysEnabled(false);
		contentPane.setFocusable(false);
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		setContentPane(contentPane);

		// TOOL BAR

		tools = new ArrayList<Tool>();
		tools.add(new ToolCreate());
		tools.add(new ToolModify());
		tools.add(new ToolEvaluate());

		toolBar = new JToolBar();
		toolBar.setFocusTraversalKeysEnabled(false);
		toolBar.setFocusable(false);
		toolBar.setBackground(Draw.brigter(toolBar.getBackground(), 0.98D));
		toolBar.setFloatable(false);

		ButtonGroup bg = new ButtonGroup();

		tglbtnCreate = new JToggleButton("Create");
		tglbtnCreate.setFocusTraversalKeysEnabled(false);
		tglbtnCreate.setFocusable(false);
		tglbtnCreate.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				do_tglbtnCreate_actionPerformed(e);
			}
		});
		toolBar.add(tglbtnCreate);
		bg.add(tglbtnCreate);

		tglbtnModify = new JToggleButton("Modify");
		tglbtnModify.setFocusTraversalKeysEnabled(false);
		tglbtnModify.setFocusable(false);
		tglbtnModify.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				do_tglbtnSelect_actionPerformed(e);
			}
		});
		toolBar.add(tglbtnModify);
		bg.add(tglbtnModify);

		tglbtnEvaluate = new JToggleButton("Evaluate");
		tglbtnEvaluate.setFocusTraversalKeysEnabled(false);
		tglbtnEvaluate.setFocusable(false);
		tglbtnEvaluate.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				do_tglbtnEvaluate_actionPerformed(arg0);
			}
		});
		toolBar.add(tglbtnEvaluate);
		bg.add(tglbtnEvaluate);

		scrlEval = new JScrollPane();
		scrlEval.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
		scrlEval.setPreferredSize(new Dimension(256, 2));
		scrlEval.setFocusTraversalKeysEnabled(false);
		scrlEval.setFocusable(false);
		scrlEval.setVisible(false);

		scrlCanvas = new JScrollPane();
		scrlCanvas.setFocusTraversalKeysEnabled(false);
		scrlCanvas.setFocusable(false);

		lblStatus = new JTextField("");
		lblStatus.setFocusTraversalKeysEnabled(false);
		lblStatus.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null));
		GroupLayout gl_contentPane = new GroupLayout(contentPane);
		gl_contentPane.setHorizontalGroup(gl_contentPane
				.createParallelGroup(Alignment.LEADING)
				.addComponent(toolBar, GroupLayout.DEFAULT_SIZE, 574, Short.MAX_VALUE)
				.addGroup(
						gl_contentPane.createSequentialGroup().addComponent(scrlEval, GroupLayout.PREFERRED_SIZE, 292, GroupLayout.PREFERRED_SIZE)
								.addPreferredGap(ComponentPlacement.RELATED).addComponent(scrlCanvas, GroupLayout.DEFAULT_SIZE, 276, Short.MAX_VALUE))
				.addComponent(lblStatus, GroupLayout.DEFAULT_SIZE, 574, Short.MAX_VALUE));
		gl_contentPane.setVerticalGroup(gl_contentPane.createParallelGroup(Alignment.LEADING).addGroup(
				gl_contentPane
						.createSequentialGroup()
						.addComponent(toolBar, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
						.addPreferredGap(ComponentPlacement.RELATED)
						.addGroup(
								gl_contentPane.createParallelGroup(Alignment.LEADING).addComponent(scrlCanvas, GroupLayout.DEFAULT_SIZE, 277, Short.MAX_VALUE)
										.addComponent(scrlEval, GroupLayout.DEFAULT_SIZE, 277, Short.MAX_VALUE)).addPreferredGap(ComponentPlacement.RELATED)
						.addComponent(lblStatus, GroupLayout.PREFERRED_SIZE, 19, GroupLayout.PREFERRED_SIZE)));
		lblStatus.addFocusListener(new FocusListener() {

			@Override
			public void focusLost(FocusEvent arg0) {
				lblStatus.requestFocus();
			}

			@Override
			public void focusGained(FocusEvent arg0) {
				if (lblStatus.getText().contains(" > "))
					lblStatus.setText("");
				pnlCanvas.repaint();
			}
		});
		lblStatus.addKeyListener(new KeyListener() {
			@Override
			public void keyTyped(KeyEvent e) {
				if (e.getKeyChar() == KeyEvent.VK_ESCAPE)
					pnlCanvas.tool().clear(thisFrame, pnlCanvas.graph);
				else if (lblStatus.getText().contains(">")) {
					lblStatus.setText("");
					lblStatus.setForeground(Color.GREEN.darker());
				}
				if (lblStatus.getForeground().equals(Color.GREEN.darker()))
					if (e.getKeyChar() == '\n')
						pnlCanvas.tool().keyType(thisFrame, graph(), e, true);
					else
						pnlCanvas.tool().keyType(thisFrame, graph(), e, false);
				pnlCanvas.repaint();

			}

			@Override
			public void keyReleased(KeyEvent e) {
				keyTyped(e);
			}

			@Override
			public void keyPressed(KeyEvent e) {}
		});

		pnlEval = new JPanel();
		pnlEval.setPreferredSize(new Dimension(256, 370));
		pnlEval.setFocusTraversalKeysEnabled(false);
		pnlEval.setFocusable(false);
		scrlEval.setViewportView(pnlEval);

		panelFunction = new PanelFunction();
		panelFunction.setPreferredSize(new Dimension(128, 128));
		panelFunction.panel.setPreferredSize(new Dimension(200, 64));

		btnEval = new JButton("Evaluate");
		btnEval.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				do_btnEval_actionPerformed(e);
			}
		});

		btnInput = new JButton("Input");
		btnInput.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent paramActionEvent) {
				do_btnInput_actionPerformed(paramActionEvent);
			}
		});

		btnOutput = new JButton("Output");
		btnOutput.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				do_btnOutput_actionPerformed(arg0);
			}
		});

		lblPaths = new JLabel("Paths");

		separator_2 = new JSeparator();

		scrollPane = new JScrollPane();
		scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);

		lblDetermenants = new JLabel("Determenants");

		separator_3 = new JSeparator();

		scrollPane_1 = new JScrollPane();
		scrollPane_1.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);

		GroupLayout gl_pnlEval = new GroupLayout(pnlEval);
		gl_pnlEval.setHorizontalGroup(gl_pnlEval
				.createParallelGroup(Alignment.LEADING)
				.addGroup(
						gl_pnlEval.createSequentialGroup().addComponent(btnInput).addPreferredGap(ComponentPlacement.RELATED).addComponent(btnOutput)
								.addContainerGap(141, Short.MAX_VALUE))
				.addComponent(panelFunction, GroupLayout.DEFAULT_SIZE, 273, Short.MAX_VALUE)
				.addGroup(gl_pnlEval.createSequentialGroup().addComponent(lblDetermenants).addContainerGap(205, Short.MAX_VALUE))
				.addGroup(gl_pnlEval.createSequentialGroup().addGap(72).addComponent(separator_3, GroupLayout.DEFAULT_SIZE, 201, Short.MAX_VALUE))
				.addComponent(scrollPane_1, GroupLayout.DEFAULT_SIZE, 273, Short.MAX_VALUE)
				.addGroup(
						gl_pnlEval.createSequentialGroup().addComponent(lblPaths).addPreferredGap(ComponentPlacement.RELATED)
								.addComponent(separator_2, GroupLayout.DEFAULT_SIZE, 232, Short.MAX_VALUE).addContainerGap())
				.addComponent(scrollPane, GroupLayout.DEFAULT_SIZE, 273, Short.MAX_VALUE)
				.addGroup(Alignment.TRAILING, gl_pnlEval.createSequentialGroup().addContainerGap().addComponent(btnEval)));
		gl_pnlEval.setVerticalGroup(gl_pnlEval.createParallelGroup(Alignment.LEADING).addGroup(
				gl_pnlEval
						.createSequentialGroup()
						.addGroup(gl_pnlEval.createParallelGroup(Alignment.BASELINE).addComponent(btnInput).addComponent(btnOutput))
						.addPreferredGap(ComponentPlacement.RELATED)
						.addComponent(panelFunction, GroupLayout.PREFERRED_SIZE, 89, GroupLayout.PREFERRED_SIZE)
						.addPreferredGap(ComponentPlacement.RELATED)
						.addGroup(
								gl_pnlEval.createParallelGroup(Alignment.TRAILING).addComponent(lblPaths)
										.addComponent(separator_2, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
						.addPreferredGap(ComponentPlacement.RELATED)
						.addComponent(scrollPane, GroupLayout.PREFERRED_SIZE, 112, GroupLayout.PREFERRED_SIZE)
						.addPreferredGap(ComponentPlacement.RELATED)
						.addGroup(
								gl_pnlEval.createParallelGroup(Alignment.TRAILING).addComponent(lblDetermenants)
										.addComponent(separator_3, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
						.addPreferredGap(ComponentPlacement.RELATED).addComponent(scrollPane_1, GroupLayout.DEFAULT_SIZE, 64, Short.MAX_VALUE)
						.addPreferredGap(ComponentPlacement.RELATED).addComponent(btnEval)));

		lstDtrm = new JList();
		lstDtrm.getSelectionModel().addListSelectionListener(new ListSelectionListener() {

			@Override
			public void valueChanged(ListSelectionEvent arg0) {
				((ToolEvaluate) tools.get(2)).selectDtrm(thisFrame, graph(), lstDtrm.getMinSelectionIndex());
			}
		});
		lstDtrm.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		scrollPane_1.setViewportView(lstDtrm);

		lstPath = new JList<ArrayList<Path<UI_Node>>>();
		lstPath.getSelectionModel().addListSelectionListener(new ListSelectionListener() {

			@Override
			public void valueChanged(ListSelectionEvent arg0) {
				((ToolEvaluate) tools.get(2)).selectPath(thisFrame, graph(), lstPath.getMinSelectionIndex());
			}
		});
		lstPath.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		scrollPane.setViewportView(lstPath);
		pnlEval.setLayout(gl_pnlEval);

		pnlCanvas = new MyCanvas(thisFrame);
		pnlCanvas.setPreferredSize(new Dimension(2000, 2000));
		pnlCanvas.setFocusTraversalKeysEnabled(false);
		pnlCanvas.setFocusable(false);
		pnlCanvas.setAlignmentY(Component.TOP_ALIGNMENT);
		pnlCanvas.setAlignmentX(Component.LEFT_ALIGNMENT);
		pnlCanvas.setBackground(Color.WHITE);
		scrlCanvas.setViewportView(pnlCanvas);
		GroupLayout gl_pnlCanvas = new GroupLayout(pnlCanvas);
		gl_pnlCanvas.setHorizontalGroup(gl_pnlCanvas.createParallelGroup(Alignment.LEADING).addGap(0, 391, Short.MAX_VALUE));
		gl_pnlCanvas.setVerticalGroup(gl_pnlCanvas.createParallelGroup(Alignment.LEADING).addGap(0, 300, Short.MAX_VALUE));
		pnlCanvas.setLayout(gl_pnlCanvas);
		contentPane.setLayout(gl_contentPane);

		tglbtnCreate.getActionListeners()[0].actionPerformed(null);
		tglbtnCreate.setSelected(true);
	}

	protected void do_tglbtnCreate_actionPerformed(ActionEvent e) {
		try {
			if (!pnlCanvas.tool().isBusy()) {
				scrlEval.setVisible(tglbtnEvaluate.isSelected());
				pnlCanvas.setTool(tools.get(0));
				revalidate();
			}
		} catch (Exception ex) {
			error("Couldn't choose create tool.");
		}
	}

	protected void do_tglbtnSelect_actionPerformed(ActionEvent e) {
		try {
			if (!pnlCanvas.tool().isBusy()) {
				scrlEval.setVisible(tglbtnEvaluate.isSelected());
				pnlCanvas.setTool(tools.get(1));
				revalidate();
			}
		} catch (Exception ex) {
			error("Couldn't choose select tool.");
		}
	}

	protected void do_tglbtnEvaluate_actionPerformed(ActionEvent arg0) {
		try {
			if (!pnlCanvas.tool().isBusy()) {
				scrlEval.setVisible(tglbtnEvaluate.isSelected());
				pnlCanvas.setTool(tools.get(2));
				revalidate();
			}
		} catch (Exception ex) {
			error("Couldn't choose evaluate tool.");
		}
	}

	protected void do_chckbxmntmGrid_actionPerformed(ActionEvent e) {
		try {
			pnlCanvas.showGrid = chckbxmntmGrid.isSelected();
			pnlCanvas.repaint();
		} catch (Exception ex) {
			error("Couldn't toggle grid.");
		}
	}

	public void status(String string) {
		lblStatus.setEditable(false);
		lblStatus.setForeground(getForeground());
		lblStatus.setText(string);
	}

	public void error(String string) {
		lblStatus.setEditable(false);
		lblStatus.setForeground(Color.RED);
		lblStatus.setText(string);
	}

	public void startInput(String string) {
		lblStatus.setEditable(true);
		lblStatus.setForeground(getForeground());
		lblStatus.setText(string + " > ");
	}

	public void stopInput() {
		lblStatus.setEditable(false);
		lblStatus.setForeground(getForeground());
		lblStatus.setText("");
	}

	public String getInput() {
		return lblStatus.getText();
	}

	private UI_SFG graph() {
		return pnlCanvas.graph;
	}

	private void setGraph(UI_SFG obj) {
		pnlCanvas.graph = obj;
	}

	protected void do_btnInput_actionPerformed(ActionEvent paramActionEvent) {
		((ToolEvaluate) tools.get(2)).input(thisFrame, graph());
	}

	protected void do_btnOutput_actionPerformed(ActionEvent arg0) {
		((ToolEvaluate) tools.get(2)).output(thisFrame, graph());
	}

	protected void do_btnEval_actionPerformed(ActionEvent e) {
		((ToolEvaluate) tools.get(2)).evaluate(thisFrame, graph(), lstPath, lstDtrm);
	}

	protected void do_mntmSave_actionPerformed(ActionEvent e) {
		try {
			JFileChooser fc = new JFileChooser();
			if (fc.showSaveDialog(this) != JFileChooser.APPROVE_OPTION)
				return;
			File f = fc.getSelectedFile();
			ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(f));
			out.writeObject(graph());
			out.close();
		} catch (Exception e1) {
			error("Couldn't save file.");
		}
	}

	protected void do_mntmOpen_actionPerformed(ActionEvent e) {
		try {
			JFileChooser fc = new JFileChooser();
			if (fc.showOpenDialog(this) != JFileChooser.APPROVE_OPTION)
				return;
			File f = fc.getSelectedFile();
			ObjectInputStream in = new ObjectInputStream(new FileInputStream(f));
			setGraph((UI_SFG) in.readObject());
			in.close();
		} catch (Exception e1) {
			error("Couldn't open file.");
		}
	}

	protected void do_mntmNew_actionPerformed(ActionEvent e) {
		pnlCanvas.graphClear();
	}
}
